package LIR;

import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import IC.BinaryOps;
import IC.AST.ArrayLocation;
import IC.AST.Assignment;
import IC.AST.Break;
import IC.AST.CallStatement;
import IC.AST.Continue;
import IC.AST.Expression;
import IC.AST.ExpressionBlock;
import IC.AST.Field;
import IC.AST.Formal;
import IC.AST.ICClass;
import IC.AST.If;
import IC.AST.Length;
import IC.AST.LibraryMethod;
import IC.AST.Literal;
import IC.AST.LocalVariable;
import IC.AST.LogicalBinaryOp;
import IC.AST.LogicalUnaryOp;
import IC.AST.MathBinaryOp;
import IC.AST.MathUnaryOp;
import IC.AST.Method;
import IC.AST.NewArray;
import IC.AST.NewClass;
import IC.AST.PrimitiveType;
import IC.AST.Program;
import IC.AST.Return;
import IC.AST.Statement;
import IC.AST.StatementsBlock;
import IC.AST.StaticCall;
import IC.AST.StaticMethod;
import IC.AST.This;
import IC.AST.UserType;
import IC.AST.VariableLocation;
import IC.AST.VirtualCall;
import IC.AST.VirtualMethod;
import IC.AST.Visitor;
import IC.AST.While;
import SymbolTable.Symbol;
import Traversal.SemanticChecker;
import TypeTable.StringType;
import TypeTable.Type;

public class TranslationVisitor implements Visitor 
{
	private List<String> m_Strings;
	private Map<String,ClassLayout> classesLayouts = new HashMap<String, ClassLayout>();
	private int regCounter = 0;
	private int labelCounter = 0;
	private int currentWhile = 0; 
	
	public TranslationVisitor()
	{
		m_Strings = new LinkedList<String>();
		classesLayouts = new HashMap<String, ClassLayout>();
	}
	
	@Override
	public Object visit(Program program) 
	{
		String classTranslations = "# Class Translations\n";
		
		for (ICClass icClass : program.getClasses())
		{
			ClassLayout layout = new ClassLayout(icClass, classesLayouts.get(icClass.getSuperClassName()));	
			classesLayouts.put(icClass.getName(), layout);
			LirTranslation classTrans = (LirTranslation)icClass.accept(this);
			classTranslations += classTrans.getTranslation();
		}
		
		String header = "# String Literals\n";
		
		for (int i = 0; i < m_Strings.size(); i++)
			//header += String.format("str%s: \"%s\"\n", i, m_Strings.get(i));
			header +="str"+i+": " +m_Strings.get(i)+"\n";
		header += "\n# Dispatch Tables\n";
		
		for (Entry<String, ClassLayout> entry : classesLayouts.entrySet())
			header += entry.getValue().getDispatchTable();
		
		String translate = header + classTranslations;
		
		return new LirTranslation(translate, "");
	}

	@Override
	public Object visit(ICClass icClass) 
	{
		String translate = "";
		
		for (Method m : icClass.getMethods()) {
			translate += ((LirTranslation) m.accept(this)).getTranslation();
		}
		
		return new LirTranslation(translate, "");
	}

	@Override
	public Object visit(Field field) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object visit(VirtualMethod method) {
		String translate = "";
		
		translate += "_" + method.getSymbolTable().getClassSymbolTable().getId() + "_" + method.getName() + ":\n";
		
		for (Statement st : method.getStatements()) {
			translate += ((LirTranslation) st.accept(this)).getTranslation();
		}
		
		
		if (method.getType().getName().compareTo("void")==0) {
			translate += "Return 9999\n";
		}
		
		
		return new LirTranslation(translate, "");
	}

	@Override
	public Object visit(StaticMethod method) {
		String translate = "";
		if	(method.getName().compareTo("main")==0)
			translate+= "_ic_main:\n";
		translate += "_" + method.getSymbolTable().getClassSymbolTable().getId() + "_" + method.getName() + ":\n";
		
		for (Statement st : method.getStatements()) {
			translate += ((LirTranslation) st.accept(this)).getTranslation();
		}
		
		if (method.getType().getName().compareTo("void")==0 && method.getName().compareTo("main")!=0) {
			translate += "Return 9999\n";
		}
		if (method.getName().compareTo("main")==0) {
			translate += "Library __exit(0), Rdummy\n";
		}
		return new LirTranslation(translate, "");
	}

	@Override
	public Object visit(LibraryMethod method) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object visit(Formal formal) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object visit(PrimitiveType type) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object visit(UserType type) {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public Object visit(Assignment assignment) 
	{
		String translate = "";
        int savedReg = regCounter;
        
		LirTranslation assign = (LirTranslation)assignment.getAssignment().accept(this);
        translate += assign.getTranslation();
        regCounter++;
        
        LirTranslation location = (LirTranslation)assignment.getVariable().accept(this);
        regCounter++;
        
        translate += location.getTranslation();
        
        String targetReg = assign.getTargetRegister();
        
        if ((assign.getType() == LirTranslation.Type.ArrayLoc &&
            location.getType() != LirTranslation.Type.Register) ||
            (assign.getType() == LirTranslation.Type.VariableLoc &&
             location.getType() == LirTranslation.Type.VariableLoc))
        {
        	targetReg = "R" + regCounter;
        	translate += assign.getMove() + assign.getTargetRegister() + ", " + targetReg + "\n";
        }
        
        translate += location.getMove()+" "+targetReg+","+location.getTargetRegister()+"\n";
        
        regCounter = savedReg;
        return new LirTranslation(translate,targetReg,location.getType());
    }

	@Override
	public Object visit(CallStatement callStatement) {
		 return callStatement.getCall().accept(this);

	}

	@Override
	public Object visit(Return returnStatement) 
	{
		String translate="";
		if (returnStatement.getValue() != null) {
			LirTranslation cmp = (LirTranslation)returnStatement.getValue().accept(this);
			translate += cmp.getTranslation();
			String tarReg = cmp.getTargetRegister();
			if (cmp.getType() != LirTranslation.Type.Register) {
				translate += cmp.getMove() + cmp.getTargetRegister() + ", R" + ++regCounter + "\n";
				tarReg = "R" + regCounter;
				regCounter--;
			}
			translate += "Return " + tarReg + "\n";
			return new LirTranslation(translate, cmp.getTargetRegister());
		} else {
			translate = "Return 9999\n";
			return new LirTranslation(translate, "");
		}
	}

	@Override
	public Object visit(If ifStatement) 
	{
		int savedReg = regCounter;
		
		String labelName = "_label"+labelCounter++;
		String translate ="";
		
		LirTranslation cmp = (LirTranslation)ifStatement.getCondition().accept(this);
		regCounter++;
		
		String cmpReg = cmp.getTargetRegister();
		
		if (cmp.getType() != LirTranslation.Type.Register)
		{
			cmpReg = "R" + regCounter;
			translate += cmp.getMove() + cmp.getTargetRegister() + ", " + cmpReg + "\n";
			regCounter++;
		}
		
		if (ifStatement.hasElse())
		{
			translate += cmp.getTranslation();					
			translate += "Compare 0, " + cmpReg + "\n";
			translate += "JumpTrue _false"+labelName+"\n";
			translate +=  ((LirTranslation) ifStatement.getOperation().accept(this)).getTranslation();
			regCounter++;
			
			translate += "Jump _end"+labelName+"\n";
			translate += "_false"+labelName+":\n";
			translate += ((LirTranslation) ifStatement.getElseOperation().accept(this)).getTranslation();
			
			translate += "_end"+labelName+":\n";
		}
		else 
		{
			translate  += cmp.getTranslation(); 
			translate += "Compare 0," + cmpReg + "\n";
			translate += "JumpTrue _end"+labelName+"\n";
			
			translate +=  ((LirTranslation) ifStatement.getOperation().accept(this)).getTranslation();
			translate += "_end"+labelName+":\n";
		}
		
		regCounter = savedReg;
		return new LirTranslation(translate, "");
	}

	@Override
	public Object visit(While whileStatement) 
	{
		int savedReg = regCounter;
		
		int oldWhileCounter = currentWhile;
		currentWhile = labelCounter;
		String labelName = "_label"+labelCounter++;
		String translate = "_test" + labelName+":\n";
		
		LirTranslation cmp = (LirTranslation)whileStatement.getCondition().accept(this);
		regCounter++;
		String cmpReg = cmp.getTargetRegister();
		
		if (cmp.getType() != LirTranslation.Type.Register)
		{
			cmpReg = "R" + regCounter;
			translate += cmp.getMove() + cmp.getTargetRegister() + ", " + cmpReg + "\n";
			regCounter++;
		}
		
		translate +=  cmp.getTranslation();
		translate += "Compare 0, " + cmpReg + "\n";
		translate += "JumpTrue _end"+labelName+"\n";
		
		translate +=  ((LirTranslation) whileStatement.getOperation().accept(this)).getTranslation();
		translate += "Jump _test"+labelName+"\n";
		translate += "_end"+labelName+":\n";
		currentWhile = oldWhileCounter;
		
		regCounter = savedReg;
		return new LirTranslation(translate, "");
	}

	@Override
	public Object visit(Break breakStatement) {
		String translate = "Jump _end_label"+currentWhile + "\n";
		return new LirTranslation(translate, "");

	}

	@Override
	public Object visit(Continue continueStatement) {
		String translate = "Jump _test_label"+currentWhile + "\n";
		return new LirTranslation(translate, "");
		
	}

	@Override
	public Object visit(StatementsBlock statementsBlock) 
	{
		 String translate = "";
		for (Statement  s : statementsBlock.getStatements())
			translate +=((LirTranslation) s.accept(this)).getTranslation();
		
		return new LirTranslation(translate, "");
	}

	@Override
	public Object visit(LocalVariable localVariable) 
	{
		int savedReg = regCounter;
		
		String translate = "";
		if (localVariable.hasInitValue())
		{
			LirTranslation init = (LirTranslation)localVariable.getInitValue().accept(this);
			regCounter++;
			
			translate += init.getTranslation();
			String targetReg = localVariable.getName() + localVariable.id;
			
	        if (init.getType() == LirTranslation.Type.ArrayLoc ||
	        	init.getType() == LirTranslation.Type.VariableLoc)
	        {
	        	targetReg = "R" + regCounter;
	        	translate += "Move " + localVariable.getName() + localVariable.id + ", " + targetReg + "\n";
	        }
			
			translate += init.getMove() + init.getTargetRegister() + ", " + targetReg +"\n"; 	
		}
		
		regCounter = savedReg;
		return new LirTranslation(translate, "");
	}

	@Override
    public Object visit(VariableLocation location)
    {   
        String translate = "";
       
        if (location.isExternal())
        {
            LirTranslation loc = (LirTranslation) location.getLocation().accept(this);
            ClassLayout layout = classesLayouts.get(location.getTypeName());
            int offset = layout.fieldToOffset.get(location.getName()) + 1;
            translate += loc.getTranslation();
            translate += "Move " + loc.getTargetRegister() + ", R" +  regCounter + "\n";
            return new LirTranslation(translate,
                                      "R" + regCounter + "." + offset,
                                      LirTranslation.Type.ExternalLoc);
        }
        else
        {
            Symbol symbol = location.getSymbolTable().lookup(location.getName(), location);
            boolean isField = symbol.getKind() == Symbol.SymbolKind.Field;
           
            if (isField)
            {
                String className = symbol.getNode().getSymbolTable().getId();
                ClassLayout layout = classesLayouts.get(className);
                int offset = layout.fieldToOffset.get(location.getName()) + 1;
                translate += "Move this, R" +  regCounter + "\n";
               
                return new LirTranslation(translate,
                                          "R" + regCounter + "." + offset,
                                          LirTranslation.Type.ExternalLoc);
            }
           
            String targetReg = location.getName();
            
            if (symbol.getKind() == Symbol.SymbolKind.Variable)
            {
            	int id = ((LocalVariable)symbol.getNode()).id;
            	targetReg += id;
        	}
            
            return new LirTranslation(translate, targetReg, LirTranslation.Type.VariableLoc);
        }
    }

	@Override
	public Object visit(ArrayLocation location) 
	{
		int savedReg = regCounter;
		regCounter++;
		LirTranslation arraytranslate = (LirTranslation) location.getArray().accept(this);
		regCounter++;
		
		String translate = arraytranslate.getTranslation(); 
		String arrReg = arraytranslate.getTargetRegister();
		
		if (arraytranslate.getType() != LirTranslation.Type.Register)
		{
			arrReg = "R" + savedReg;
			translate += arraytranslate.getMove() + arraytranslate.getTargetRegister() + ", " + arrReg + "\n";
		}
		
		LirTranslation arrayIndex = (LirTranslation) location.getIndex().accept(this);
		translate += arrayIndex.getTranslation();
		
		regCounter = savedReg;
		return new LirTranslation(translate,
								  arrReg +"["+arrayIndex.getTargetRegister()+"]", 
								  LirTranslation.Type.ArrayLoc);
	}

	@Override
	public Object visit(StaticCall call) 
	{
		String translate = "";
		String argList = "";
		int regStart = regCounter++;

		if (call.getClassName().equals("Library"))
		{
			int first = 1;
			for (Expression arg: call.getArguments())
			{
				LirTranslation argExp = (LirTranslation) arg.accept(this);
				translate += argExp.getTranslation();
				String targetReg = argExp.getTargetRegister();
				
				if (argExp.getType() != LirTranslation.Type.Literal &&
					argExp.getType() != LirTranslation.Type.Register)
				{
					targetReg = "R" + regCounter++;
					translate += argExp.getMove() + argExp.getTargetRegister() + ", " + targetReg + "\n";
				}
				
				if (first ==0) argList+=",";
				argList += targetReg;
				first = 0;
				regCounter++;
			}

			translate += "Library __"+call.getName()+"(";
			translate += argList +"),R"+regStart+"\n";
			
			regCounter = regStart;
			
			return new LirTranslation(translate, regStart);

		}

		//Symbol funcSym = call.getSymbolTable().lookup(call.getName(), call);
		//List<Formal> formals = ((StaticMethod) funcSym.getNode()).getFormals();
		List<Formal> formals = call.staticMethod.getFormals();
		int i = 0;
		for (Expression arg : call.getArguments()) {
			LirTranslation l = (LirTranslation) arg.accept(this);
			translate += l.getTranslation();
			if (i!=0) {
				argList += ",";
			}
			argList += formals.get(i).getName() + "=" + l.getTargetRegister();
			regCounter++;
			i++;
		}
		
		regCounter = regStart;
		translate += "StaticCall _" + call.getClassName() + "_" + call.getName() + "(" + argList + "), R" + regCounter + "\n";
		
		return new LirTranslation(translate, regCounter);
		
	}

	@Override
	public Object visit(VirtualCall call) 
	{
		int regStart = regCounter;
		regCounter++;
		int resultReg = regCounter;
		regCounter++;
		
		String className = call.className;
		ClassLayout layout = classesLayouts.get(className);
		
		int offset = layout.getMethodOffset(className, call.getName());
		String translate = "";
		
		String targetReg;
		if (call.isExternal()) {
			LirTranslation l = (LirTranslation) call.getLocation().accept(this);
			regCounter++;
			
			targetReg = l.getTargetRegister();
			translate += l.getTranslation();
			
			if (l.getType() != LirTranslation.Type.Register)
			{
				targetReg = "R" + regCounter; 
				translate += l.getMove() + l.getTargetRegister() + ", " + targetReg + "\n";
			}
		} 
		else {
			targetReg = "R" + regCounter++;
			translate += "Move this ," + targetReg + "\n"; 
		}
		
		String argList = "";
		
		regCounter++;
		
		//Symbol funcSym = call.getSymbolTable().lookup(call.getName(), call);
		//List<Formal> formals = ((VirtualMethod) funcSym.getNode()).getFormals();
		List<Formal> formals = call.virtualMethod.getFormals();
		int i = 0;
		for (Expression arg : call.getArguments()) {
			LirTranslation argExp = (LirTranslation) arg.accept(this);
			translate += argExp.getTranslation();
			
			String argReg = argExp.getTargetRegister(); 
			
			if (argExp.getType() != LirTranslation.Type.Literal &&
				argExp.getType() != LirTranslation.Type.Register)
			{
				argReg = "R" + regCounter++;
				translate += argExp.getMove() + argExp.getTargetRegister() + ", " + argReg + "\n";
			}
			
			if (i!=0) argList += ",";
			argList += formals.get(i).getName() + "=" + argReg;
			regCounter++;
			i++;
		}
		
		translate += "VirtualCall " + targetReg + "." + offset + "(" + argList + "), R" + resultReg + "\n";
		regCounter = regStart;
		return new LirTranslation(translate, resultReg);
	}

	@Override
	public Object visit(This thisExpression) 
	{
		String teanslate = "Move this,R"+regCounter+"\n";
		return new LirTranslation(teanslate, regCounter);
	}

	@Override
	public Object visit(NewClass newClass) 
	{
		int savedReg = regCounter;
		regCounter++;
		ClassLayout newClassLayOut = classesLayouts.get(newClass.getName());
		String translate = "Library __allocateObject("+newClassLayOut.getSize()+"),R"+savedReg+"\n";
		translate += "MoveField _DV_"+ newClassLayOut.getClassName()+",R"+savedReg+".0\n";
		regCounter = savedReg;
		return new LirTranslation(translate, savedReg);
	}

	@Override
	public Object visit(NewArray newArray) 
	{
		int savedReg = regCounter;
		regCounter++;
		LirTranslation size = (LirTranslation)newArray.getSize().accept(this);
		regCounter++;
		
		String translate = size.getTranslation();
		//translate += "__checkSize(" + size.getTargetRegister() + ")\n";
		String sizeReg = size.getTargetRegister();
		
		if (size.getType() != LirTranslation.Type.Register)
		{
			sizeReg = "R" + regCounter;
			translate += size.getMove() + size.getTargetRegister() + ", " + sizeReg + "\n";
		}
		
		translate += String.format("Mul 4, %s\n", sizeReg);
		translate += String.format("Library __allocateArray(%s), R%s\n", 
								   sizeReg,
								   savedReg);
		
		regCounter = savedReg;
		return new LirTranslation(translate, savedReg);
	}

    @Override
    public Object visit(Length length)
    {
        int savedReg = regCounter;
        LirTranslation arr = (LirTranslation)length.getArray().accept(this);
        int targetReg = regCounter++;
       
        String translate = arr.getTranslation();
        //translate += "__checkNullRef(R" + arr.getTargetRegister() + ")\n";
        String arrReg = arr.getTargetRegister();
       
        if (arr.getType() != LirTranslation.Type.Register &&
            arr.getType() != LirTranslation.Type.VariableLoc)
        {
            arrReg = "R" + regCounter;
            translate += arr.getMove() + arr.getTargetRegister() + ", " + arrReg + "\n";
        }
       
        translate += String.format("ArrayLength %s, R%s\n",
                                   arrReg,
                                   targetReg);
       
        regCounter = savedReg;
        return new LirTranslation(translate, targetReg);
    }

	@Override
    public Object visit(MathBinaryOp binaryOp) {
        int savedReg = regCounter;
       
        Type firstOp = (Type) binaryOp.getFirstOperand().accept(new SemanticChecker());
        LirTranslation right = (LirTranslation)binaryOp.getFirstOperand().accept(this);
        regCounter++;  
        LirTranslation left = (LirTranslation)binaryOp.getSecondOperand().accept(this);
        regCounter++;

       
        String translate = right.getTranslation() + left.getTranslation();
        String regLeft = left.getTargetRegister();
       
        regCounter++;
        if (left.getType() != LirTranslation.Type.Register &&
            left.getType() != LirTranslation.Type.VariableLoc &&
            left.getType() != LirTranslation.Type.Literal)
        {
            regLeft = "R" + regCounter;
            translate += left.getMove() + left.getTargetRegister() + ", " + regLeft + "\n";
            regCounter++;
        }

        String regRight = right.getTargetRegister();
       
        if (right.getType() != LirTranslation.Type.Register)
        {
            regRight = "R" + regCounter;
            translate += right.getMove() + right.getTargetRegister() + ", " + regRight + "\n";
            regCounter++;
        }
       
        if (firstOp instanceof StringType) {
           
            translate += "Library __stringCat(" + regRight + "," + regLeft + "), " + regLeft + "\n";
            regCounter = savedReg;

            return new LirTranslation(translate, left.getTargetRegister());
        }
       
        String op = null;
       
        switch (binaryOp.getOperator())
        {
            case PLUS:
                op = "Add";
                break;
            case MINUS:
                op = "Sub";
                break;
            case MULTIPLY:
                op ="Mul";
                break;
            case DIVIDE:
                op = "Div";
                break;
            case MOD:
                op = "Mod";
                break;
            default:
                throw new RuntimeException("Unrecognized op");
        }
       
        translate += String.format("%s %s, %s\n", op, regLeft, regRight);
        translate += String.format("Move %s, R%s\n", regRight, savedReg);     
   
        regCounter = savedReg;
       
        return new LirTranslation(translate, savedReg);
    }

	@Override
	public Object visit(LogicalBinaryOp binaryOp) {
		int savedReg = regCounter;
		
		LirTranslation left = (LirTranslation)binaryOp.getFirstOperand().accept(this);
		regCounter++;
		LirTranslation right = (LirTranslation)binaryOp.getSecondOperand().accept(this);
		regCounter++;
		
		String translate = left.getTranslation();
		String regLeft = left.getTargetRegister();
		
		if (left.getType() != LirTranslation.Type.Register &&
			left.getType() != LirTranslation.Type.VariableLoc &&
			left.getType() != LirTranslation.Type.Literal)
		{
			regLeft = "R" + regCounter;
			translate += left.getMove() + left.getTargetRegister() + ", " + regLeft + "\n";
			regCounter++;
		}

		translate += right.getTranslation();
		String regRight = right.getTargetRegister();
		
		if (right.getType() != LirTranslation.Type.Register)
		{
			regRight = "R" + regCounter;
			translate += right.getMove() + right.getTargetRegister() + ", " + regRight + "\n";
			regCounter++;
		}
		
		if (binaryOp.getOperator() == BinaryOps.LOR ||
			binaryOp.getOperator() == BinaryOps.LAND)
		{
			translate += String.format("%s %s, %s\n", 
										binaryOp.getOperator() == BinaryOps.LOR ? "Or":"And",
										regLeft, 
										regRight);
			
			 translate+="Move "+regRight+",R"+savedReg+"\n";
			   labelCounter++;
			   regCounter = savedReg;
			   
			   return new LirTranslation(translate, savedReg);
		}
		else
		{
			translate += String.format("Compare %s, %s\n", regLeft, regRight);
		
			switch (binaryOp.getOperator())
			{
				case EQUAL:
					translate += String.format("JumpTrue _test_logical_true" + labelCounter + "\n");
					break;
				case GT:
					translate += String.format("JumpL _test_logical_true" + labelCounter + "\n");
					break;
				case GTE:
					translate += String.format("JumpLE _test_logical_true" + labelCounter + "\n");
					break;
				case LT:
					translate += String.format("JumpG_test_logical_true" + labelCounter + "\n");
					break;
				case LTE:
					translate += String.format("JumpGE _test_logical_true" + labelCounter + "\n");
					break;
				case NEQUAL:
					translate += String.format("JumpFalse _test_logical_true" + labelCounter + "\n");
					break;
				default:
					throw new RuntimeException("Unrecognized op");
			}
			
			translate += String.format("Move 0, R%s\n", savedReg);	
			translate += "Jump _test_logical_end" + labelCounter + "\n";
			translate += "_test_logical_true" + labelCounter + ":\n";
			translate += String.format("Move 1, R%s\n", savedReg);
			translate += "_test_logical_end" + labelCounter + ":\n";
		}
		
		labelCounter++;
		regCounter = savedReg;
		
		return new LirTranslation(translate, savedReg);
	}

	
	
	
	

    @Override
    public Object visit(MathUnaryOp unaryOp)
    {
        int savedReg = regCounter;
        LirTranslation expr = (LirTranslation)unaryOp.getOperand().accept(this);
        regCounter++;
       
        String translate = expr.getTranslation();
        String targetReg = "R" + savedReg;
        translate += expr.getMove() + expr.getTargetRegister() + ", " + targetReg + "\n";
       
        String target = "R" + regCounter;
        expr.setTargetRegister(target);
        
        switch (unaryOp.getOperator())
        {
            case UMINUS:
                translate += "Neg " + targetReg + "\n";
                break;
            default:
                throw new RuntimeException("Unknown op");
        }

        regCounter = savedReg;
        return new LirTranslation(translate, targetReg);
    }

    @Override
    public Object visit(LogicalUnaryOp unaryOp)
    {
        int savedReg = regCounter;
        LirTranslation expr = (LirTranslation)unaryOp.getOperand().accept(this);
        regCounter++;
       
        String translate = expr.getTranslation();
        String targetReg = "R" + regCounter;
        translate += expr.getMove() + expr.getTargetRegister() + ", " + targetReg + "\n";
       
        switch (unaryOp.getOperator())
        {
            case LNEG:
                translate += "Not " + targetReg + "\n";
                break;
            default:
                throw new RuntimeException("Unknown op");
        }

        regCounter = savedReg;
        return new LirTranslation(translate, targetReg);
    }
    
    
	@Override
	public Object visit(Literal literal) 
	{
		String translate = "";
		String reg = "";
		LirTranslation.Type type = LirTranslation.Type.Literal;
		
		switch (literal.getType())
		{
			case NULL:
			case FALSE:
				reg = "0";
				break;
			case TRUE:
				reg = "1";
				break;
			case INTEGER:
				reg = literal.getValue().toString();
				break;
			case STRING:
				String val = (String)literal.getValue();
				int index = m_Strings.size();
				m_Strings.add(val);
				
				reg = "R" + regCounter;
				type = LirTranslation.Type.Register;
				
				translate = "Move str" + index + ", " + reg + "\n";
				break;
			default:
				throw new RuntimeException("Unknown literal");
		}

		return new LirTranslation(translate, reg, type);
	}

	@Override
	public Object visit(ExpressionBlock expressionBlock) {
		// TODO Auto-generated method stub
		return null;
	}

}
